using System.IO;
using System.Collections.Generic;
using System;
using System.Text.RegularExpressions;

namespace cssp
{
	/// <summary>
	/// Parsed file
	/// </summary>
	public class CssxScanner : ICssxScanner
	{
		enum ScannerState { Normal, CommentBlock }

		ScannerState mState;
		int mLineNum;
		int mOffset; // distance up to start of current line

		TokenDelegate mOnToken;
		public TokenDelegate OnToken
		{
			get { return mOnToken; }
			set { mOnToken = value; }
		}

		public int LineNumber
		{
			get { return mLineNum; }
		}

		public void Scan(TextReader reader)
		{
			mState = ScannerState.Normal;
			mLineNum = 0;
			mOffset = 0;

			string line = reader.ReadLine();
			while (line != null)
			{
				mLineNum++;
				if (line.Length > 0)
					ScanLine(line);
				mOffset += line.Length + Environment.NewLine.Length;
				line = reader.ReadLine();
			}
		}

		void ScanLine(string line)
		{
			// Strip comment fom line (if it is single-line) and continue, or set state to comment-block, and return
			int boc = line.IndexOf("/*");
			int eoc = line.IndexOf("*/");

			if (boc > -1)
			{
				if (eoc > -1)
					line = line.Remove(boc, (eoc - boc + 2));
				else
					mState = ScannerState.CommentBlock;
			}
			else if (eoc > -1)
			{
				line = line.Remove(0, (eoc + 2));
				mState = ScannerState.Normal;
			}

			if (mState == ScannerState.CommentBlock)
				return;

			Token[] tokens = Tokenize(line);
			if (tokens.Length == 0)
				return;

			OnToken(tokens);
		}

		Token[] Tokenize(string line)
		{
			//Match match = Regex.Match(line, @"(?<="")[^""\\]*(?:\\.[^""\\]*)*(?="")|\w+");

			List<Token> tokens = new List<Token>();
			//while (match.Success)
			//{
			//	tokens.Add(new Token(mLineNum, match.Index, mOffset + match.Index, match.Value.Replace("\\\"", "\"")));
			//	match = match.NextMatch();
			//}
			//return tokens.ToArray();
			
			int state = 0; // 0=between words (not in quotes), 1=in a word, 2=in quotes
			int ch = 0, start = 0;
			string value = String.Empty;

			while (ch < line.Length)
			{
				switch (line[ch])
				{
					case ' ':
					case '	':
						if (state == 1)
						{
							value = line.Substring(start, (ch - start));
							tokens.Add(new Token(TokenType.Word, mLineNum, start+1, mOffset + start, value));
							state = 0;
						}
						break;
					case '"':
						// ignore escaped quotes
						if (ch > 0 && line[ch - 1] == '\\')
							break;

						if (state == 0)
						{
							start = ch;
							state = 2;
						}
						else if (state == 1)
						{
							if ((ch - start) > 0)
							{
								value = line.Substring(start, (ch - start));
								tokens.Add(new Token(TokenType.Word, mLineNum, start+1, mOffset + start, value));
							}
							state = 2;
						}
						else if (state == 2)
						{
							// get text BETWEEN quotes
							value = line.Substring(start + 1, (ch - start - 1));
							tokens.Add(new Token(TokenType.QuotedString, mLineNum, start+1, mOffset + start, value.Replace("\\\"", "\"")));
							state = 0;
						}
						break;
					default:
						if (state == 0)
						{
							start = ch;
							state = 1;
						}
						break;
				}
				ch++;
			} // while

			if (state == 1 && (ch - start) > 0)
			{
				value = line.Substring(start, (ch - start));
				tokens.Add(new Token(TokenType.Word, mLineNum, start+1, mOffset + start, value));
			}

			return tokens.ToArray();
		}


		//void OnError(string message)
		//{
		//    mNumErrors++;
		//    if (mErorrHandler != null)
		//        mErorrHandler.Error(Filename, message);
		//    else
		//        System.Diagnostics.Debug.WriteLine(Filename + ": " + message);
		//}
	}
}
